package com.eunion.web.common.base;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.eunion.core.LogUtil;
import com.eunion.core.PageData;
import com.eunion.core.common.JsonVo;
import com.eunion.core.exception.ProjectException;
import com.eunion.web.common.vo.Web;

/**
 * 基类，提供一些基础方法.
 * <p>
 * 主要为规定子类行为.
 * 
 * 
 * @version 2016年4月12日 下午8:27:58
 * @param <T>
 * @param <ID>
 */
public abstract class BaseUiController<T, ID extends Serializable> {

	/**
	 * 日志 子类也可用 .
	 */
	private Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 获取基本的Service服务类，用于处理基本的逻辑.
	 * 
	 * @return 基本的Service服务
	 */
	protected abstract BaseService<T, ID> getBaseService();

	/**
	 * 跳转到首页面.
	 * 
	 * @param model
	 *            a holder for model attributes 数据
	 * @return 首页页面
	 */
	@RequestMapping(value = Web.URL_SEPARATOR, method = { RequestMethod.GET, RequestMethod.POST })
	public String main(PageData<T> pages, Model model) {
		// model.addAttribute(Web.MENU, getWebPageVo());
		return getUrlPrefix();
	}
	
	/**
	 * 获取泛型实例.
	 * 
	 * @return 实体.
	 */
	@SuppressWarnings("unchecked")
	public T getT() {
		try {
			Type sType = getClass().getGenericSuperclass();
			Type[] generics = ((ParameterizedType) sType).getActualTypeArguments();
			Class<T> mTClass = (Class<T>) (generics[0]);
			return mTClass.newInstance();
		} catch (InstantiationException e) {
			logger.error("实例化出错", e);
			throw new ProjectException("获取实例出错 ", e);
		} catch (IllegalAccessException e) {
			logger.error("实例化出错", e);
			throw new ProjectException("获取实例出错 ", e);
		}
	}

	/**
	 * get 时 跳转到首页页面.
	 * 
	 * @param obj
	 *            实体对象
	 * @param model
	 *            a holder for model attributes 数据
	 * @return 首页页面
	 */
	@RequestMapping(value = "/save", method = { RequestMethod.GET })
	String saveGet(T obj, Model model) {
		return main(null, model);
	}

	/**
	 * get 时 跳转到首页页面.
	 * 
	 * @param obj
	 *            实体对象
	 * @param model
	 *            a holder for model attributes 数据
	 * @return 首页页面
	 */
	@RequestMapping(value = "/update", method = { RequestMethod.GET })
	String updateGet(T obj, Model model) {
		return main(null, model);
	}

	/**
	 * 跳转到更新页面.
	 * 
	 * @param id
	 *            实体对象的主键
	 * @param model
	 *            a holder for model attributes 数据
	 * @return 查看页面
	 */
	@RequestMapping(value = Web.URL_SEP_VIEW + "/{id}", method = RequestMethod.GET)
	String view(@PathVariable ID id, Model model) {
		// setModule(model);
		T objDb = getBaseService().findOne(id);
		model.addAttribute(Web.OBJ, objDb);
		return getUrlPrefix().concat("-view");
	}

	/**
	 * 跳转到新增页面.
	 * 
	 * @param model
	 *            a holder for model attributes 数据
	 * @return 新增页面
	 */
	@RequestMapping(value = Web.URL_SEP_ADD, method = RequestMethod.GET)
	String add(Model model) {
		// setModule(model);
		model.addAttribute(Web.OBJ, getT());
		return getUrlPrefix().concat("-add");
	}

	/**
	 * 跳转到更新页面.
	 * 
	 * @param id
	 *            待更新的对象ID
	 * @param model
	 *            a holder for model attributes 数据
	 * @return 更新页面
	 */
	@RequestMapping(value = Web.URL_SEP_UPDATE + "/{id}", method = RequestMethod.GET)
	String edit(@PathVariable ID id, Model model) {
		// setModule(model);
		T objDb = getBaseService().findOne(id);
		model.addAttribute(Web.OBJ, objDb);
		return getUrlPrefix().concat("-edit");
	}

	/**
	 * 根据传入的数据ids,来删除对象.
	 */
	@RequestMapping(value = Web.URL_SEP_REMOVE, method = RequestMethod.POST, headers = {
			"Content-type=application/json" })
	// @ResponseStatus(value = HttpStatus.OK)
	@ResponseBody
	public JsonVo remove(@RequestBody List<ID> ids) {
		try {
			if (ids != null && ids.size() > 0) {
				//  2016-01-10 这里肯定要修改为批删除的，而且要重写Responsitory里的内容？
				List<T> tts = getBaseService().findAll(ids);
				if (tts != null && !tts.isEmpty()) {
					getBaseService().delete(tts);
				}
				// for (ID id : ids) {
				// getBaseService().delete(id);
				// }
			}
			return new JsonVo(true);
		} catch (Exception e) {
			LogUtil.get(this.getClass()).error("remove erro ", e);
			return new JsonVo(false, "删除出现异常");
		}
	}

	/**
	 * 分页ajax数据请求.
	 * 
	 * @param params
	 *            请求参数
	 * @return 返回分页数据
	 */
	@RequestMapping(value = "/page.json", method = { RequestMethod.POST })
	@ResponseBody
	protected PageData<T> page(@RequestBody PageData<T> params) {
		if (null == params)
			params = new PageData<T>();
		params.calculate();
		Integer size = params.getLimit();
		if (null == size || size < PageData.PAGE_SIZE_DEFAULT) {
			size = PageData.PAGE_SIZE_DEFAULT;
		}
		Integer offset = params.getOffset();// offset是最后的数目
		Integer frompage = PageData.DEFAULT_1;
		if (null != offset) {
			frompage = offset / size;
		} else {
			frompage = params.getPageNumber();
		}
		Pageable pageAble = new PageRequest(frompage, size);
		Page<T> page = getBaseService().findAll(getCondition(params), pageAble);
		// PageData<T> pageBt = new PageData<T>(page.getTotalElements(),
		// page.getContent());
		// pageBt.setPageNumber(params.getPageNumber());
		params.setTotal(page.getTotalElements());
		params.setRows(page.getContent());
		params.calculate();
		LogUtil.get(this.getClass()).debug("PageData int total {} , rows {} ", params.getTotal(), params.getRows());
		return params;
	}

	/**
	 * 根据前台头面生成查询条件.
	 * 
	 * @param params
	 *            参数
	 * @return 返回查询条件
	 */
	protected Specification<T> getCondition(final PageData<T> params) {
		return new Specification<T>() {
			@Override
			public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> list = new ArrayList<Predicate>();

				// String name = params.getKeyString("name");
				// if (!StringUtils.isBlank(name))
				// {
				// list.add(cb.like(root.get("name").as(String.class), "%" +
				// name + "%"));
				// }
				//
				// Integer age = params.getKeyInt("age");
				// if (age != null)
				// {
				// list.add(cb.equal(root.get("age").as(Long.class),
				// Long.valueOf(age)));
				// }

				Predicate[] p = new Predicate[list.size()];
				// query.where(cb.and(p3,cb.or(p1,p2)));
				query.where(cb.and(list.toArray(p)));
				setOrder(root, query, cb, params);
				return query.getRestriction();
			}
		};
	}

	/**
	 * 设置默认排序 .
	 * 
	 * @param root
	 *            Root
	 * @param query
	 *            CriteriaQuery
	 * @param cb
	 *            CriteriaBuilder
	 * @param params
	 *            PageParams参数
	 */
	protected void setOrder(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb, PageData<T> params) {
		// if (!params.isDesc()) if (CommonUtil.isEmpty(params.getSort()))
		query.orderBy(cb.desc(root.get("timeCreate").as(Date.class)));
	}

	/** 所属的module , module一般为Controller类名的去掉controller后的小写. */
	private String module = this.getClass().getSimpleName().toLowerCase().replaceAll("controller", "");

	/**
	 * 获取url的基类.
	 */
	protected String getUrlPrefix() {
		return module.concat(Web.URL_SEPARATOR).concat(module);
	}
}
